package com.qiall.game.gobang.command;

import com.alibaba.fastjson.JSON;
import com.qiall.game.gobang.GobangUtil;
import com.qiall.game.gobang.RoomPool;
import com.qiall.game.gobang.event.GameEndEvent;
import com.qiall.game.gobang.kafka.DataKafkaQueue;
import com.qiall.game.gobang.kafka.Protocol;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 发送移动命令
 */
@Component("sendMoveCommandService")
@Slf4j
public class SendMoveCommandService implements CommandService {

    @Autowired
    private DataKafkaQueue dataKafkaQueue;

    @Autowired
    private ApplicationContext applicationContext;


    @Override
    public String getCommand() {
        return CommandEnum.MOVE.getCode();
    }

    /**
     * 操作 建立连接判断是否有空闲的房间如果有则进入房间 返回对局开始
     */
    @Override
    public void process(Protocol protocol) {
        //check 判断落子x,y 是否合法
        ReturnData data = JSON.parseObject(protocol.getData(), ReturnData.class);
        RoomPool.Room room = RoomPool.getRoom(data.getRoomId());
        List<RoomPool.Room.Point> points= room.getCheckerboard().stream().filter(x->x.getX()==data.getMoveX()&&x.getY()==data.getMoveY()).collect(Collectors.toList());

        if (points!=null&&points.size()>0) {
            return;
        }
        //判断是否重复落子 重复落子直接返回
        if (!protocol.getSessionId().equals(room.getCurrentMoveSession())) {
            return;
        }
        if(room.getRoomStatus().equals(RoomPool.Room.end)){
            log.error("game end");
            return;
        }

        String toSessionId = null;
        if (room.getSessionId1().equals(protocol.getSessionId())) {
            toSessionId = room.getSessionId2();
        }
        if (room.getSessionId2().equals(protocol.getSessionId())) {
            toSessionId = room.getSessionId1();
        }

        // 落子
        makeMoveInMemory(protocol, room, data);

        // 检测是否胜利
        boolean isSuccess = GobangUtil.check(room.getCheckerboard(), data.moveX, data.moveY);
        if(isSuccess){
            applicationContext.publishEvent(new GameEndEvent(this
                    , room.getRoomId()));
        }

        // 发送移动命令
        sendMoveCommand(protocol, isSuccess, toSessionId);

        // 设置可以移动的为toSessionId
        room.setCurrentMoveSession(toSessionId);

    }

    private void sendMoveCommand(Protocol protocol, boolean isSuccess, String toSessionId) {
        ReturnData data = JSON.parseObject(protocol.getData(), ReturnData.class);
        RoomPool.Room room = RoomPool.getRoom(data.getRoomId());
        ReturnData returnData = new ReturnData();
        returnData.setRoomId(room.getRoomId());
        String fromSessionId = protocol.getSessionId();

        // 发送移动命令
        Protocol protocolTo = buildProtocolTrans(data, toSessionId, isSuccess);
        dataKafkaQueue.sedSocketMessage(protocolTo);
        // 发送ack确认消息
        Protocol protocolAck = buildProtocolAck(data, fromSessionId, isSuccess);
        dataKafkaQueue.sedSocketMessage(protocolAck);
    }

    private void makeMoveInMemory(Protocol protocol, RoomPool.Room room, ReturnData data) {
        //设置棋盘以及session状态

        if (protocol.getSessionId().equals(room.getSessionId1())) {
            RoomPool.Room.Point point=new RoomPool.Room.Point();
            point.setSessionId( RoomPool.Room.sessionId1L);
            point.setX(data.moveX);
            point.setY(data.moveY);
            room.getCheckerboard().add(point);
            room.setCurrentMoveSession(room.getSessionId2());
        } else if (protocol.getSessionId().equals(room.getSessionId2())) {
            RoomPool.Room.Point point=new RoomPool.Room.Point();
            point.setSessionId( RoomPool.Room.sessionId2L);
            point.setX(data.moveX);
            point.setY(data.moveY);
            room.getCheckerboard().add(point);
            room.setCurrentMoveSession(room.getSessionId1());
        }
    }

    private Protocol buildProtocolTrans(ReturnData data, String toSessionId, boolean isSuccess) {
        Protocol protocolTo = new Protocol();
        protocolTo.setCommand(CommandEnum.MOVE.getCode());
        protocolTo.setSessionId(toSessionId);
        if (isSuccess) {
            data.setIsSuccess(false);
            data.setIsEnd(true);
        } else {
            data.setIsEnd(false);
        }
        protocolTo.setData(JSON.toJSONString(data));
        return protocolTo;
    }

    private Protocol buildProtocolAck(ReturnData data, String fromSessionId, Boolean isSuccess) {
        Protocol protocolAck = new Protocol();
        protocolAck.setCommand(CommandEnum.MOVE_ACK.getCode());
        ReturnData returnDataAck = new ReturnData();
        if (isSuccess) {
            returnDataAck.setIsSuccess(true);
            returnDataAck.setIsEnd(true);
        } else {
            returnDataAck.setIsEnd(false);
        }
        returnDataAck.setMoveX(data.getMoveX());
        returnDataAck.setMoveY(data.getMoveY());
        returnDataAck.setRoomId(data.getRoomId());
        protocolAck.setData(JSON.toJSONString(returnDataAck));
        protocolAck.setSessionId(fromSessionId);
        return protocolAck;
    }

    @Data
    public static class ReturnData {
        Integer roomId;
        Integer moveX;
        Integer moveY;
        Boolean isSuccess;
        Boolean isEnd;
    }
}
